package serverMgr

import (
	"encoding/json"
	"fmt"
	"path"
	"sync"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef/protomsg"
	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
)

type IServerMap interface {
	//加入服务器信息
	Put(sinfo IServerInfo)
	//删除一个服务器信息
	Delete(path string)
	//更新Load值
	UpLoad(path string, val int64) IServerInfo
	//根据负载逻辑，获取服务器
	GetBalancing(sType, sGroup uint32) (result IServerInfo, err error)
	//获取指定类型服务器列表
	GetListByType(sType uint32) ([]IServerInfo, error)
	//获取组的指定类型服务器列表
	GetListByTypeAGroup(sType, sGroup uint32) ([]IServerInfo, error)
	//获取指定服务器
	GetServerByID(sType, sGroup uint32, serverId uint64) (result IServerInfo, err error)
	//删除所有服务器信息
	DeleteAll()
	// 监听函数
	WatchCallDelay(evt *clientv3.Event)
	// 加载全量
	LoadWatchAll(key string)

	//设置管理器
	SetExt(ext IExt)
}

// 随机负载
type ServerMapByRand struct {
	ext  IExt //外部对象，一般是Service
	Lock sync.RWMutex
	//服务器信息
	Srvli map[uint64]map[uint64]IServerInfo
}

func NewServerMapByRand() (result *ServerMapByRand) {
	result = new(ServerMapByRand)
	result.Srvli = make(map[uint64]map[uint64]IServerInfo)
	return
}

// 加入服务器信息
func (this *ServerMapByRand) Put(sinfo IServerInfo) {
	this.Lock.Lock()
	defer this.Lock.Unlock()
	key := uint64(sinfo.GetSrvType())<<32 + uint64(sinfo.GetGroupID())
	if li, ok := this.Srvli[key]; !ok {
		li = make(map[uint64]IServerInfo)
		this.Srvli[key] = li
		li[sinfo.GetServerID()] = sinfo
	} else {
		li[sinfo.GetServerID()] = sinfo
	}

}

// 删除一个服务器信息
func (this *ServerMapByRand) Delete(path string) {
	groupid, stype, serverid := GetPathServerInfo(path)
	this.Lock.Lock()
	defer this.Lock.Unlock()
	key := uint64(stype)<<32 + uint64(groupid)
	if li, ok := this.Srvli[key]; ok {
		delete(li, serverid)
	}
}

// 更新Load值
func (this *ServerMapByRand) UpLoad(path string, val int64) IServerInfo {
	this.Lock.Lock()
	defer this.Lock.Unlock()
	groupid, stype, sid := GetPathServerInfo(path)
	key := uint64(stype)<<32 + uint64(groupid)
	if li, ok := this.Srvli[key]; ok {
		if sinfo, ok := li[sid]; ok {
			sinfo.SetLoad(val)
			return sinfo
		}
	}
	return nil
}

// 更新服务器状态
func (this *ServerMapByRand) UpStatus(path string, val int32) {
	this.Lock.Lock()
	defer this.Lock.Unlock()
	groupid, stype, sid := GetPathServerInfo(path)
	key := uint64(stype)<<32 + uint64(groupid)
	if li, ok := this.Srvli[key]; ok {
		if sinfo, ok := li[sid]; ok {
			sinfo.SetStatus(val)
		}
	}
}

// 根据负载逻辑，获取服务器
func (this *ServerMapByRand) GetBalancing(stype, groupid uint32) (result IServerInfo, err error) {
	this.Lock.RLock()
	defer this.Lock.RUnlock()
	result = nil
	key := uint64(stype)<<32 + uint64(groupid)
	srvlen := 0
	if li, ok := this.Srvli[key]; ok {
		srvlen = len(li)
		for _, v := range li {
			if v.GetStatus() != protomsg.ServerStatus_DefaultOK {
				continue
			}
			if v.GetLoad() < 80 {
				return v, nil
			} else if v.GetLoad() < 90 {
				if result == nil {
					result = v
				} else if result != nil && result.GetLoad() > v.GetLoad() {
					result = v
				}
			} else if result == nil {
				result = v
			}
		}
	}
	if result == nil {
		return result, fmt.Errorf("Server list is empty, Type %d SrvLen: %d", stype, srvlen)
	}
	return
}

// 获取指定类型服务器列表
func (this *ServerMapByRand) GetListByType(styp uint32) (result []IServerInfo, err error) {
	this.Lock.RLock()
	defer this.Lock.RUnlock()
	result = make([]IServerInfo, 0, len(this.Srvli)*10)
	for _, li := range this.Srvli {
		for _, v := range li {
			if v.GetSrvType() != styp {
				break
			}
			result = append(result, v)
		}
	}
	return
}

// 获取组的指定类型服务器列表
func (this *ServerMapByRand) GetListByTypeAGroup(sType, sGroup uint32) (result []IServerInfo, err error) {
	this.Lock.RLock()
	defer this.Lock.RUnlock()
	key := uint64(sType)<<32 + uint64(sGroup)
	if li, ok := this.Srvli[key]; ok {
		result = make([]IServerInfo, len(li))
		i := 0
		for _, v := range li {
			result[i] = v
			i++
		}
	}
	return
}

// 获取指定服务器
func (this *ServerMapByRand) GetServerByID(stype, groupid uint32, serverId uint64) (result IServerInfo, err error) {
	this.Lock.RLock()
	defer this.Lock.RUnlock()
	key := uint64(stype)<<32 + uint64(groupid)
	if li, ok := this.Srvli[key]; ok {
		if sinfo, ok := li[serverId]; ok {
			return sinfo, nil
		}
	}
	return nil, fmt.Errorf("Cant get server, Type %d  Id %d not existed", stype, serverId)

}

// 删除所有服务器信息
func (this *ServerMapByRand) DeleteAll() {
	this.Lock.RLock()
	defer this.Lock.RUnlock()
	this.Srvli = make(map[uint64]map[uint64]IServerInfo)
}

// 监听函数
func (this *ServerMapByRand) WatchCallDelay(evt *clientv3.Event) {
	if evt.Type == mvccpb.PUT {
		//有服务器信息过来
		var sinfo IServerInfo
		_, sidstr := path.Split(string(evt.Kv.Key))
		groupid, stype, sid := GetPathServerInfo(string(evt.Kv.Key))
		_, _ = groupid, sid
		switch sidstr {
		case PATH_LOAD:
			//如果是状态更新
			val := common.NewString(string(evt.Kv.Value)).ToInt64V()
			sinfo = this.UpLoad(string(evt.Kv.Key), val)
		case PATH_STATUS:
			val := common.NewString(string(evt.Kv.Value)).ToInt64V()
			this.UpStatus(string(evt.Kv.Key), int32(val))
		case PATH_INFO:
			//服务器主信息更新、
			sinfo = this.ext.NewInfo(stype)
			if err := json.Unmarshal(evt.Kv.Value, sinfo); err != nil {
				//可能需要输出信息
				return
			}
			this.Put(sinfo)
			logger.Debug(logger.LogKey_Etcd, "WatchCallDelay put PATH_INFO:", string(evt.Kv.Key), sinfo)
		default:
			logger.Debug(logger.LogKey_Etcd, "WatchCallDelay put unknown:", string(evt.Kv.Key), sinfo)
		}
		if sinfo != nil {
			//监听的服务器信息更新，判断是否需要连接
			this.ext.WatchInfoCallBack(sinfo)
		}
	} else if evt.Type == mvccpb.DELETE {
		_, sidstr := path.Split(string(evt.Kv.Key))
		if sidstr == PATH_INFO {
			//删一个服务器信息
			this.Delete(string(evt.Kv.Key))
			logger.Debug(logger.LogKey_Etcd, "WatchCallDelay delete PATH_INFO:", string(evt.Kv.Key))
		}
	}
}
func (this *ServerMapByRand) LoadWatchAll(key string) {
	// logger.Fatal("LoadWatchAll")
	res, err := this.ext.GetEtcd().GetPathAll(key)
	if err != nil {
		logger.Error("loadWatchAll:", err)
		return
	}
	logger.Debug(logger.LogKey_Etcd, "LoadWatchAll", key, len(res.Kvs))
	for _, kv := range res.Kvs {
		var sinfo IServerInfo
		_, sidstr := path.Split(string(kv.Key))
		groupid, stype, sid := GetPathServerInfo(string(kv.Key))
		_, _ = groupid, sid
		switch sidstr {
		case PATH_LOAD:
			//如果是状态更新
			val := common.NewString(string(kv.Value)).ToInt64V()
			sinfo = this.UpLoad(string(kv.Key), val)
			logger.Debugf(logger.LogKey_Etcd, "LoadWatchAll LoadInfo %s %+v", key, sinfo)
		case PATH_INFO:
			sinfo = this.ext.NewInfo(stype)
			if err := json.Unmarshal(kv.Value, sinfo); err != nil {
				//可能需要输出信息
				continue
			}
			this.Put(sinfo)
			logger.Debugf(logger.LogKey_Etcd, "LoadWatchAll PathInfo %s %+v", key, sinfo)
		default:
			logger.Debug(logger.LogKey_Etcd, "unknown Key:", string(kv.Key), sinfo)
		}
		if sinfo != nil {
			//监听的服务器信息更新，判断是否需要连接
			this.ext.WatchInfoCallBack(sinfo)
		}
	}
}

// 设置管理器
func (this *ServerMapByRand) SetExt(ext IExt) {
	this.ext = ext
}
